﻿using System;
using System.Text;

namespace LeRenard.Core.Cryptography
{
    /// <summary>
    /// Defines an abstract cryptographer base.
    /// </summary>
    public abstract class CryptographerBase : ICryptographer
    {
        /// <summary>
        /// Gets the encryptor.
        /// </summary>
        protected IEncryptor Encryptor { get { return _encryptor; } }
        private readonly IEncryptor _encryptor;

        /// <summary>
        /// Determines whether an encryptor is specified.
        /// </summary>        
        public bool HasEncryptor { get { return _encryptor != null; } }

        /// <summary>
        /// Gets the decryptor.
        /// </summary>
        protected IDecryptor Decryptor { get { return _decryptor; } }
        private readonly IDecryptor _decryptor;

        /// <summary>
        /// Determines whether a decryptor is specified.
        /// </summary>        
        public bool HasDecryptor { get { return _decryptor != null; } }

        /// <summary>
        /// Creates a new <see cref="Base64Cryptographer"/>.
        /// </summary>
        /// <param name="encoding">The encoding to be used.</param>
        public CryptographerBase(Encoding encoding, IEncryptor encryptor = null, IDecryptor decryptor = null)
        {
            ThrowIf.Null(() => encoding);

            _decryptor = decryptor;
            _encryptor = encryptor;
        }

        /// <summary>
        /// Encrypts the specified input.
        /// </summary>
        /// <param name="input">The input to be encrypted.</param>
        /// <returns>The input encrypted as a base64 string.</returns>
        public virtual string Encrypt(string input)
        {
            if (HasEncryptor) {
                return _encryptor.Encrypt(input);
            } else {
                throw new Exception("No encryptor defined.");
            }
        }

        /// <summary>
        /// Encrypts the specified input.
        /// </summary>
        /// <param name="input">The input to be encrypted.</param>        
        /// <returns>The input encrypted as a base64 string.</returns>
        public string Encrypt(byte[] input)
        {
            if (HasEncryptor) {
                return _encryptor.Encrypt(input);
            } else {
                throw new Exception("No encryptor defined.");
            }
        }

        /// <summary>
        /// Decrypts the specified input.
        /// </summary>
        /// <param name="input">The input to be decrypted.</param>
        /// <returns>The base64 string input to it's decrypted form.</returns>
        public virtual string Decrypt(string input)
        {
            if (HasDecryptor) {
                return _decryptor.Decrypt(input);
            } else {
                throw new Exception("No decryptor defined.");
            }
        }

        /// <summary>
        /// Decrypts the specified input.
        /// </summary>
        /// <param name="input">The input to be decrypted.</param>
        /// <returns>The base64 string input to it's decrypted form.</returns>
        public virtual string Decrypt(byte[] input)
        {
            if (HasDecryptor) {
                return _decryptor.Decrypt(input);
            } else {
                throw new Exception("No decryptor defined.");
            }
        }
    }
}
